# -*- coding: utf-8 -*-
"""
DTM验证工具 - 图形界面应用模块
提供现代化的用户界面，基于模块化架构重构
"""

import os
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
from threading import Thread
from typing import List, Dict, Any, Optional
from datetime import datetime

from config_manager import Constants
from dtm_controller import DTMController


class DTMMainWindow:
    """DTM主窗口类"""

    def __init__(self, root: tk.Tk):
        self.root = root
        self.controller = DTMController()
        self.constants = Constants()

        # 界面状态
        self.processing = False
        self.selected_items: List[str] = []

        # 设置窗口
        self._setup_window()

        # 创建界面组件
        self._create_widgets()

        # 绑定控制器回调
        self._setup_controller_callbacks()

        # 显示初始提示
        self._show_initial_help()

    def _setup_window(self):
        """设置窗口属性"""
        self.root.title(self.constants.UI_TEXTS["app_title"])
        self.root.geometry("1000x700")
        self.root.minsize(800, 600)

        # 设置窗口图标（如果存在）
        try:
            icon_path = os.path.join(os.path.dirname(__file__), "icon.ico")
            if os.path.exists(icon_path):
                self.root.iconbitmap(icon_path)
        except:
            pass  # 忽略图标设置错误

    def _create_widgets(self):
        """创建界面组件"""
        # 主容器
        self.main_frame = ttk.Frame(self.root)
        self.main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        # 创建各个部分
        self._create_toolbar()
        self._create_file_list_section()
        self._create_control_section()
        self._create_progress_section()
        self._create_log_section()
        self._create_status_bar()

    def _create_toolbar(self):
        """创建工具栏"""
        toolbar_frame = ttk.Frame(self.main_frame)
        toolbar_frame.pack(fill=tk.X, pady=(0, 10))

        # 文件操作按钮
        ttk.Button(toolbar_frame, text="添加文件", command=self._add_files).pack(
            side=tk.LEFT, padx=(0, 5)
        )

        ttk.Button(toolbar_frame, text="添加文件夹", command=self._add_directory).pack(
            side=tk.LEFT, padx=(0, 5)
        )

        ttk.Button(toolbar_frame, text="移除选中", command=self._remove_selected).pack(
            side=tk.LEFT, padx=(0, 5)
        )

        ttk.Button(toolbar_frame, text="清空列表", command=self._clear_list).pack(
            side=tk.LEFT, padx=(0, 15)
        )

        # 配置操作按钮
        ttk.Button(toolbar_frame, text="导入配置", command=self._import_config).pack(
            side=tk.LEFT, padx=(0, 5)
        )

        ttk.Button(toolbar_frame, text="导出配置", command=self._export_config).pack(
            side=tk.LEFT, padx=(0, 15)
        )

        # 帮助按钮
        ttk.Button(toolbar_frame, text="格式说明", command=self._show_format_help).pack(
            side=tk.RIGHT, padx=(5, 0)
        )

        ttk.Button(toolbar_frame, text="关于", command=self._show_about).pack(
            side=tk.RIGHT, padx=(5, 0)
        )

    def _create_file_list_section(self):
        """创建文件列表区域"""
        # 文件列表框架
        list_frame = ttk.LabelFrame(self.main_frame, text="文件列表")
        list_frame.pack(fill=tk.BOTH, expand=True, pady=(0, 10))

        # 创建Treeview
        columns = ("file_path", "file_name", "fixed_height", "file_size", "status")
        self.file_tree = ttk.Treeview(
            list_frame, columns=columns, show="headings", height=8
        )

        # 设置列标题和宽度
        self.file_tree.heading("file_path", text="完整路径")
        self.file_tree.heading("file_name", text="文件名")
        self.file_tree.heading("fixed_height", text="基准高程 (m)")
        self.file_tree.heading("file_size", text="文件大小")
        self.file_tree.heading("status", text="状态")

        self.file_tree.column("file_path", width=300, minwidth=200)
        self.file_tree.column("file_name", width=200, minwidth=150)
        self.file_tree.column("fixed_height", width=120, minwidth=100)
        self.file_tree.column("file_size", width=100, minwidth=80)
        self.file_tree.column("status", width=120, minwidth=100)

        # 添加滚动条
        scrollbar_y = ttk.Scrollbar(
            list_frame, orient=tk.VERTICAL, command=self.file_tree.yview
        )
        scrollbar_x = ttk.Scrollbar(
            list_frame, orient=tk.HORIZONTAL, command=self.file_tree.xview
        )
        self.file_tree.configure(
            yscrollcommand=scrollbar_y.set, xscrollcommand=scrollbar_x.set
        )

        # 布局
        self.file_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar_y.pack(side=tk.RIGHT, fill=tk.Y)
        scrollbar_x.pack(side=tk.BOTTOM, fill=tk.X)

        # 绑定选择事件
        self.file_tree.bind("<<TreeviewSelect>>", self._on_file_select)
        self.file_tree.bind("<Double-1>", self._on_file_double_click)

    def _create_control_section(self):
        """创建控制区域"""
        control_frame = ttk.Frame(self.main_frame)
        control_frame.pack(fill=tk.X, pady=(0, 10))

        # 左侧：批量高程设置
        left_frame = ttk.Frame(control_frame)
        left_frame.pack(side=tk.LEFT)

        ttk.Label(left_frame, text="批量设置高程:").pack(side=tk.LEFT)

        self.batch_height_var = tk.DoubleVar(value=10.0)
        height_entry = ttk.Entry(
            left_frame, textvariable=self.batch_height_var, width=10
        )
        height_entry.pack(side=tk.LEFT, padx=(5, 0))

        ttk.Button(
            left_frame, text="应用到选中", command=self._apply_batch_height
        ).pack(side=tk.LEFT, padx=(5, 0))

        # 右侧：主要操作按钮
        right_frame = ttk.Frame(control_frame)
        right_frame.pack(side=tk.RIGHT)

        ttk.Button(
            right_frame, text="打开输出目录", command=self._open_output_dir
        ).pack(side=tk.LEFT, padx=(0, 5))

        ttk.Button(right_frame, text="清理输出", command=self._cleanup_output).pack(
            side=tk.LEFT, padx=(0, 10)
        )

        self.process_button = ttk.Button(
            right_frame, text="开始批量处理", command=self._start_processing
        )
        self.process_button.pack(side=tk.LEFT)

    def _create_progress_section(self):
        """创建进度区域"""
        # 进度条（初始隐藏）
        self.progress_frame = ttk.Frame(self.main_frame)
        # 不立即pack，需要时再显示

        ttk.Label(self.progress_frame, text="处理进度:").pack(side=tk.LEFT)

        self.progress_bar = ttk.Progressbar(
            self.progress_frame, orient=tk.HORIZONTAL, mode="determinate"
        )
        self.progress_bar.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(5, 0))

        self.progress_label = ttk.Label(self.progress_frame, text="0/0")
        self.progress_label.pack(side=tk.LEFT, padx=(5, 0))

    def _create_log_section(self):
        """创建日志区域"""
        log_frame = ttk.LabelFrame(self.main_frame, text="处理日志")
        log_frame.pack(fill=tk.BOTH, expand=True)

        # 创建文本框和滚动条
        self.log_text = tk.Text(log_frame, height=6, wrap=tk.WORD)
        log_scrollbar = ttk.Scrollbar(
            log_frame, orient=tk.VERTICAL, command=self.log_text.yview
        )
        self.log_text.configure(yscrollcommand=log_scrollbar.set)

        # 布局
        self.log_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        log_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)

        # 日志操作按钮
        log_button_frame = ttk.Frame(log_frame)
        log_button_frame.pack(fill=tk.X, pady=(5, 0))

        ttk.Button(log_button_frame, text="清空日志", command=self._clear_log).pack(
            side=tk.LEFT
        )

        ttk.Button(log_button_frame, text="保存日志", command=self._save_log).pack(
            side=tk.LEFT, padx=(5, 0)
        )

    def _create_status_bar(self):
        """创建状态栏"""
        self.status_bar = ttk.Label(
            self.root, text=self.constants.UI_TEXTS["status_ready"], relief=tk.SUNKEN
        )
        self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)

    def _setup_controller_callbacks(self):
        """设置控制器回调函数"""
        self.controller.set_callbacks(
            progress_callback=self._on_progress_update,
            status_callback=self._on_status_update,
            log_callback=self._on_log_update,
        )

    # 事件处理方法
    def _add_files(self):
        """添加文件"""
        file_paths = filedialog.askopenfilenames(
            title="选择Excel文件",
            filetypes=[
                ("Excel文件", "*.xlsx"),
                ("Excel文件", "*.xls"),
                ("所有文件", "*.*"),
            ],
        )

        added_count = 0
        for file_path in file_paths:
            if self.controller.add_file(file_path, self.batch_height_var.get()):
                added_count += 1

        if added_count > 0:
            self._refresh_file_list()
            self._log(f"成功添加 {added_count} 个文件")

    def _add_directory(self):
        """添加文件夹"""
        directory = filedialog.askdirectory(title="选择包含Excel文件的文件夹")

        if directory:
            # 询问是否递归扫描
            recursive = messagebox.askyesno(
                "扫描选项",
                "是否扫描子文件夹中的Excel文件？\n\n是：递归扫描所有子文件夹\n否：仅扫描当前文件夹",
                default="no",
            )

            added_count = self.controller.add_files_from_directory(
                directory, self.batch_height_var.get(), recursive
            )

            if added_count > 0:
                self._refresh_file_list()
                self._log(f"从文件夹添加了 {added_count} 个文件")
            else:
                messagebox.showinfo("提示", "该文件夹中没有找到Excel文件")

    def _remove_selected(self):
        """移除选中的文件"""
        selected_items = self.file_tree.selection()

        if not selected_items:
            messagebox.showwarning("提示", "请先选择要移除的文件")
            return

        removed_count = 0
        for item in selected_items:
            file_path = self.file_tree.item(item)["values"][0]
            if self.controller.remove_file(file_path):
                removed_count += 1

        if removed_count > 0:
            self._refresh_file_list()
            self._log(f"移除了 {removed_count} 个文件")

    def _clear_list(self):
        """清空列表"""
        if messagebox.askyesno("确认", "确定要清空所有文件吗？"):
            self.controller.clear_files()
            self._refresh_file_list()
            self._log("已清空文件列表")

    def _apply_batch_height(self):
        """应用批量高程设置"""
        selected_items = self.file_tree.selection()

        if not selected_items:
            messagebox.showwarning("提示", "请先选择要设置高程的文件")
            return

        try:
            new_height = self.batch_height_var.get()

            # 更新选中文件的高程
            updated_count = 0
            for item in selected_items:
                file_path = self.file_tree.item(item)["values"][0]
                # 移除旧配置并添加新配置
                self.controller.remove_file(file_path)
                if self.controller.add_file(file_path, new_height):
                    updated_count += 1

            if updated_count > 0:
                self._refresh_file_list()
                self._log(f"更新了 {updated_count} 个文件的基准高程为 {new_height}")

        except tk.TclError:
            messagebox.showerror("错误", "请输入有效的高程数值")

    def _start_processing(self):
        """开始处理"""
        if self.processing:
            return

        file_list = self.controller.get_file_list()
        if not file_list:
            messagebox.showerror("错误", "请先添加要处理的文件")
            return

        # 检查是否有无效文件
        invalid_files = [f for f in file_list if not f["is_valid"]]
        if invalid_files:
            result = messagebox.askyesno(
                "警告",
                f"发现 {len(invalid_files)} 个无效文件，是否继续处理其余文件？\n\n"
                "点击'是'继续处理有效文件\n点击'否'取消处理",
            )
            if not result:
                return

        # 在新线程中执行处理
        self.processing = True
        self._show_progress()
        self.process_button.config(text="处理中...", state=tk.DISABLED)

        Thread(target=self._process_thread, daemon=True).start()

    def _process_thread(self):
        """处理线程"""
        try:
            result = self.controller.process_batch()

            # 在主线程中更新UI
            self.root.after(0, self._on_processing_complete, result)

        except Exception as e:
            self.root.after(0, self._on_processing_error, str(e))

    def _on_processing_complete(self, result: Dict[str, Any]):
        """处理完成回调"""
        self.processing = False
        self._hide_progress()
        self.process_button.config(text="开始批量处理", state=tk.NORMAL)

        if result["success"]:
            summary = result["summary"]
            messagebox.showinfo(
                "处理完成",
                f"批量处理完成！\n\n"
                f"成功处理: {summary['successful_files']} 个文件\n"
                f"处理失败: {summary['failed_files']} 个文件\n"
                f"成功率: {summary['success_rate']:.1f}%\n"
                f"总体积: {summary['total_volume']:.4f} 立方米\n\n"
                f"结果已保存到输出目录",
            )

            # 询问是否打开输出目录
            if messagebox.askyesno("提示", "是否打开输出目录查看结果？"):
                self._open_output_dir()
        else:
            messagebox.showerror("处理失败", f"批量处理失败：\n{result['error']}")

        # 刷新文件列表状态
        self._refresh_file_list()

    def _on_processing_error(self, error: str):
        """处理错误回调"""
        self.processing = False
        self._hide_progress()
        self.process_button.config(text="开始批量处理", state=tk.NORMAL)

        messagebox.showerror("处理错误", f"处理过程中发生错误：\n{error}")

    def _open_output_dir(self):
        """打开输出目录"""
        if not self.controller.open_output_directory():
            messagebox.showwarning("提示", "输出目录不存在或无法打开")

    def _cleanup_output(self):
        """清理输出目录"""
        if messagebox.askyesno("确认", "确定要清理输出目录中的所有文件吗？"):
            deleted_count = self.controller.cleanup_output()
            messagebox.showinfo("完成", f"已清理 {deleted_count} 个文件")

    def _import_config(self):
        """导入配置"""
        file_path = filedialog.askopenfilename(
            title="选择配置文件",
            filetypes=[("JSON文件", "*.json"), ("所有文件", "*.*")],
        )

        if file_path:
            if self.controller.import_configuration(file_path):
                self._refresh_file_list()
                messagebox.showinfo("成功", "配置导入成功")
            else:
                messagebox.showerror("错误", "配置导入失败，请检查文件格式")

    def _export_config(self):
        """导出配置"""
        file_path = filedialog.asksaveasfilename(
            title="保存配置文件",
            defaultextension=".json",
            filetypes=[("JSON文件", "*.json"), ("所有文件", "*.*")],
        )

        if file_path:
            if self.controller.export_configuration(file_path):
                messagebox.showinfo("成功", "配置导出成功")
            else:
                messagebox.showerror("错误", "配置导出失败")

    def _show_format_help(self):
        """显示格式说明"""
        messagebox.showinfo(
            "文件格式说明", self.constants.UI_TEXTS["file_format_warning"]
        )

    def _show_about(self):
        """显示关于信息"""
        about_text = """DTM批量验证工具 v2.0

功能特点：
• 批量处理Excel格式的DTM数据
• 自动三角剖分和体积计算
• 三维可视化和报告生成
• 模块化架构，稳定可靠

适用场景：
• 地形测量数据验证
• 土方量计算
• 三维地形建模

技术支持：Python + Tkinter + Matplotlib"""

        messagebox.showinfo("关于", about_text)

    def _show_initial_help(self):
        """显示初始帮助提示"""
        if messagebox.askyesno(
            "欢迎使用DTM批量验证工具",
            "欢迎使用DTM批量验证工具！\n\n"
            "使用前请确认您的Excel文件格式正确：\n"
            "• 无表头，第一行为数据\n"
            "• 列顺序：点名称、X坐标、Y坐标、Z坐标\n\n"
            "是否查看详细格式说明？",
        ):
            self._show_format_help()

    # 界面更新方法
    def _refresh_file_list(self):
        """刷新文件列表"""
        # 清空现有项目
        for item in self.file_tree.get_children():
            self.file_tree.delete(item)

        # 添加文件信息
        file_list = self.controller.get_file_list()
        for file_info in file_list:
            file_path = file_info["file_path"]
            file_name = os.path.basename(file_path)
            fixed_height = file_info["fixed_height"]
            file_size = self._format_file_size(file_info["file_size"])
            status = (
                "有效"
                if file_info["is_valid"]
                else f"无效: {file_info['error_message']}"
            )

            # 根据状态设置不同的标签
            tags = ["valid"] if file_info["is_valid"] else ["invalid"]

            self.file_tree.insert(
                "",
                "end",
                values=(file_path, file_name, fixed_height, file_size, status),
                tags=tags,
            )

        # 设置标签样式
        self.file_tree.tag_configure("valid", foreground="black")
        self.file_tree.tag_configure("invalid", foreground="red")

        # 更新状态栏
        total_files = len(file_list)
        valid_files = sum(1 for f in file_list if f["is_valid"])
        self._update_status_bar(f"文件: {valid_files}/{total_files} 有效")

    def _format_file_size(self, size_bytes: int) -> str:
        """格式化文件大小"""
        if size_bytes < 1024:
            return f"{size_bytes} B"
        elif size_bytes < 1024 * 1024:
            return f"{size_bytes / 1024:.1f} KB"
        else:
            return f"{size_bytes / (1024 * 1024):.1f} MB"

    def _show_progress(self):
        """显示进度条"""
        self.progress_frame.pack(fill=tk.X, pady=(0, 10))

    def _hide_progress(self):
        """隐藏进度条"""
        self.progress_frame.pack_forget()

    def _update_status_bar(self, message: str):
        """更新状态栏"""
        self.status_bar.config(text=message)

    def _log(self, message: str):
        """添加日志"""
        timestamp = datetime.now().strftime("%H:%M:%S")
        log_entry = f"[{timestamp}] {message}\n"

        self.log_text.insert(tk.END, log_entry)
        self.log_text.see(tk.END)

    def _clear_log(self):
        """清空日志"""
        self.log_text.delete(1.0, tk.END)
        self.controller.clear_log()

    def _save_log(self):
        """保存日志"""
        file_path = filedialog.asksaveasfilename(
            title="保存日志文件",
            defaultextension=".txt",
            filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")],
        )

        if file_path:
            try:
                log_content = self.log_text.get(1.0, tk.END)
                with open(file_path, "w", encoding="utf-8") as f:
                    f.write(log_content)
                messagebox.showinfo("成功", "日志保存成功")
            except Exception as e:
                messagebox.showerror("错误", f"保存日志失败：{str(e)}")

    # 控制器回调方法
    def _on_progress_update(self, current: int, total: int):
        """进度更新回调"""

        def update_ui():
            self.progress_bar["maximum"] = total
            self.progress_bar["value"] = current
            self.progress_label.config(text=f"{current}/{total}")

        self.root.after(0, update_ui)

    def _on_status_update(self, status: str):
        """状态更新回调"""
        status_map = {
            "idle": "准备就绪",
            "processing": "处理中...",
            "completed": "处理完成",
            "error": "处理错误",
        }

        display_status = status_map.get(status, status)
        self.root.after(0, self._update_status_bar, display_status)

    def _on_log_update(self, message: str):
        """日志更新回调"""
        self.root.after(0, self._log, message.split("] ", 1)[-1])  # 移除时间戳前缀

    # 事件处理
    def _on_file_select(self, event):
        """文件选择事件"""
        selected_items = self.file_tree.selection()
        self.selected_items = selected_items

    def _on_file_double_click(self, event):
        """文件双击事件"""
        selected_items = self.file_tree.selection()
        if selected_items:
            item = selected_items[0]
            file_path = self.file_tree.item(item)["values"][0]

            # 简单的高程编辑对话框
            self._edit_file_height(file_path)

    def _edit_file_height(self, file_path: str):
        """编辑文件高程"""
        # 获取当前高程
        file_list = self.controller.get_file_list()
        current_height = None
        for file_info in file_list:
            if file_info["file_path"] == file_path:
                current_height = file_info["fixed_height"]
                break

        if current_height is None:
            return

        # 创建编辑对话框
        dialog = tk.Toplevel(self.root)
        dialog.title("编辑基准高程")
        dialog.geometry("300x150")
        dialog.resizable(False, False)
        dialog.transient(self.root)
        dialog.grab_set()

        # 居中显示
        dialog.geometry(
            "+%d+%d" % (self.root.winfo_rootx() + 50, self.root.winfo_rooty() + 50)
        )

        # 内容
        ttk.Label(dialog, text=f"文件: {os.path.basename(file_path)}").pack(pady=10)
        ttk.Label(dialog, text="基准高程:").pack()

        height_var = tk.DoubleVar(value=current_height)
        height_entry = ttk.Entry(dialog, textvariable=height_var, width=15)
        height_entry.pack(pady=5)
        height_entry.select_range(0, tk.END)
        height_entry.focus()

        # 按钮
        button_frame = ttk.Frame(dialog)
        button_frame.pack(pady=15)

        def save_height():
            try:
                new_height = height_var.get()
                self.controller.remove_file(file_path)
                if self.controller.add_file(file_path, new_height):
                    self._refresh_file_list()
                    self._log(
                        f"更新文件 {os.path.basename(file_path)} 的基准高程为 {new_height}"
                    )
                dialog.destroy()
            except tk.TclError:
                messagebox.showerror("错误", "请输入有效的数值")

        ttk.Button(button_frame, text="保存", command=save_height).pack(
            side=tk.LEFT, padx=5
        )
        ttk.Button(button_frame, text="取消", command=dialog.destroy).pack(
            side=tk.LEFT, padx=5
        )

        # 绑定回车键
        height_entry.bind("<Return>", lambda e: save_height())


def create_and_run_gui():
    """创建并运行GUI应用"""
    root = tk.Tk()
    app = DTMMainWindow(root)

    try:
        root.mainloop()
    except KeyboardInterrupt:
        print("应用被用户中断")
    except Exception as e:
        print(f"应用运行时发生错误: {e}")
        import traceback

        traceback.print_exc()


if __name__ == "__main__":
    create_and_run_gui()
